/* 
 * MCore Extensions for TTBlue
 * Creates a wrapper for TTAudioObjects that can be used to build an audio processing graph.
 * Copyright © 2008, Timothy Place
 * 
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html 
 */

#ifndef __MULTICORE_H__
#define __MULTICORE_H__

#include "TTBlueAPI.h"


enum MCoreProcessStatus {
	kProcessUnknown = 0,
	kProcessNotStarted,
	kProcessingCurrently,	
	kProcessComplete
};

enum MCoreFlags {
	kMCoreProcessor = 0,
	kMCoreGenerator = 1
};

class MCoreObject;
typedef MCoreObject*	MCoreObjectPtr;


#ifdef TT_PLATFORM_WIN
	#include "windows.h"
	#ifdef _DLL_EXPORT
		#define MULTICORE_EXPORT __declspec(dllexport)
	#else
		#define MULTICORE_EXPORT __declspec(dllimport)
	#endif
#else // TT_PLATFORM_MAC
	#ifdef _DLL_EXPORT
		#define MULTICORE_EXPORT __attribute__((visibility("default")))
	#else
		#define MULTICORE_EXPORT  
	#endif
#endif


/**
	A graph may have many objects.
 
	An object may have many inlets.
	An inlet may have many signals connected.
	A signal may have many channels.
*/
class MCoreInlet {
	TTUInt16				numSources;					///< The number of getSamples callback functions (sources) for each inlet from which we pull.
	TTUInt16*				audioSourceOutletIndices;
	MCoreObject*			owner;
//	TTAudioSignal*			audioInput;					///< The buffered input for processing audio with our object.  Provided to the "inputs" array.
	TTUInt16				index;						///< What inlet am I?
public:
	MCoreObjectPtr*			audioSources;				///< An array of objects from which we pull our source samples using the ::getAudioOutput() method.
	TTAudioSignalArray*		inputs;
	
public:
	MCoreInlet();
	~MCoreInlet();
	
	void setOwner(MCoreObjectPtr newOwner, TTAudioSignalArray* newInputs, TTUInt16 newIndex);
	
	// reset
	void reset();
	
	// init the chain from which we will pull
	void init();
	
	void prepareToProcess();
	
	// collect and sum the sources
	void pull();
	
	// when we receive a notification than an object is going away...
	void drop(TTObjectPtr theObjectBeingDeleted);
	
	TTErr addSource(TTObjectPtr anObject, TTUInt16 sourceOutletNumber);

	TTUInt16 getMaxNumSourceChannels(TTUInt16 weDeliverNumChannels);
	
private:
	TTUInt16 initAudioSignal(TTAudioSignalPtr aSignal, MCoreObjectPtr aSource);

};



/**
	The MCoreObject wraps a TTBlue object in way that makes it possible to 
	build a dynamic graph of audio processing units.
 
	It is implemented as a TTObject so that it can receive dynamically bound messages, 
	such as notifications from other objects.
*/

class MULTICORE_EXPORT MCoreObject : public TTObject {	
protected:
	MCoreProcessStatus		processStatus;				///< Used to enable correct processing of feedback loops, multiple destinations, etc.
	MCoreFlags				flags;						///< Indicate special properties, such as kMCoreGenerator
	MCoreInlet*				inlets;						///< Array of Inlets

public:
	TTUInt16				inChansToOutChansRatio[2];	///< for every N incoming channels, this object should produce M output channels.
	TTUInt16				numInlets;					///< The number of inlets from which we pull
	TTAudioObject*			audioObject;				///< The actual TTBlue object doing the processing.
	TTAudioSignalArray*		inputs;						///< The buffered input for processing audio with our object.
	TTAudioSignalArray*		outputs;					///< The results of processing audio with our object.
	
	
	// Methods

	/**	Constructor.	
		@param	arguments		There should be two arguments: 
								1. The name of the TTBlue object you want to wrap, and
								2. The initial number of channel. */
	MCoreObject(TTValue& arguments);
	
	/**	Destructor.		*/
	virtual ~MCoreObject();

	/**	A notification that the specified object is being deleted -- so we should drop it from our list of input sources.  */
	TTErr objectFreeing(const TTValue& theObjectBeingDeleted);

	/**	Rather than use the internal audio output signal, it is possible to set your own.
		One example for why you might want this is for creating generator objects.	*/
	TTErr setAudioOutputPtr(TTAudioSignalArrayPtr newOutputPtr);

	TTErr setInChansToOutChansRatio(TTUInt16 numInputChannels, TTUInt16 numOutputChannels);
	//TTErr setAlwaysProcessSidechain(TTBoolean newValue);
	
	TTUInt16 getNumOutputChannels(TTUInt16 signalIndex);
	TTUInt16 getSampleRate();
	TTUInt16 getOutputVectorSize(TTUInt16 signalIndex);
	TTErr addFlag(MCoreFlags newFlag);
	
	
	/**	Clear the list of source objects from which this object will try to pull audio.	
		@param	vs		The global vector size that will be used for the chain's output.	*/
	TTErr resetSources(TTUInt16 vs);
	
	
	/**	Add a source to the list of objects from which to request audio.
		@param	anObject		The lydbaer object which is supplying us with input.
		@param	anInletNumber	If this object has a second input mechanism (e.g. a sidechain input), then that is indicated here.
								Typically the value passed here will be 0, indicating the normal audio input.
		@return					An error code.	*/
	TTErr addSource(MCoreObjectPtr anObject, TTUInt16 sourceOutletNumber=0, TTUInt16 anInletNumber=0);

	
	/**	Allocate buffers and prepare for processing.	*/
	TTErr init();
	
	
	/**	This method is called by an object about to process audio, prior to calling getAudioOutput().
		As with the getAudioOutput() method, this is driven by the destination object and working up through the chains.
		@return 		An error code.		*/
	virtual TTErr prepareToProcess();
	
	
	/**	This method is required to be implemented by all objects except for those existing solely as a destination.
		@param	audioOutput		This method is passed a reference to an audio signal pointer.
								We then set this audio signal pointer to point to the TTAudioSignal containing our calculated samples.
		@param	outletNumber	The number of the outlet (audio signal) which we want to get;
	 	@return					An error code.	*/
	virtual TTErr getAudioOutput(TTAudioSignalPtr& returnedSignal, TTUInt16 outetNumber=0);

};


MULTICORE_EXPORT void MCoreInit(void);


#endif // __MULTICORE_H__
